package com.fintech.third.service.sms;

import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.fintech.common.util.PropertiesUtils;
import com.fintech.common.util.RedisUtils;
import com.fintech.third.constant.DataRow;
import com.fintech.third.constant.ResponseResult;
import com.fintech.third.constant.SmsTypeEnum;
import com.fintech.third.dao.sms.SmsLogMapper;
import com.fintech.third.dao.sms.SmsTemplateNewMapper;
import com.fintech.third.model.message.MicroNetResponse;
import com.fintech.third.model.sms.SmsLog;
import com.fintech.third.model.sms.SmsParameter;
import com.fintech.third.model.sms.SmsTemplateNew;
import com.fintech.third.utils.HttpUtil;
import com.fintech.third.utils.ThirdSystemUtil;
import com.marvels.common.utils.MarvelsLogUtil;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
/**
 * 短信
 * @author lvgb
 *
 */

@Service("smsService")
public class SmsServiceImpl implements SmsService {

	@Autowired
	private SmsTemplateNewMapper smsTemplateMapper;
	
	@Autowired
	private SmsLogMapper smsLogMapper;

	/**
	 * 验证验证码
	 * @param mobileNo 手机号
	 * @param smsCode  验证码
	 * @param type     发送类型
	 * @return
	 */
	@Override
	public boolean checkCode(String mobileNo, String smsCode, String type){
		String timeoutStr = PropertiesUtils.getString("sms.codetimeout");
		int timeoutInt = StrUtil.isEmpty(timeoutStr) ? 900 : Integer.valueOf(timeoutStr);//验证码失效时间默认为900秒，可在配置文件中设置
		String redisCodeKey = type + mobileNo + "code";
		String redisNumKey = type + mobileNo + "num";
		// 兼容整合后因为redis反序列化问题
		Object codeRedis = null;
		try {
			codeRedis = RedisUtils.getInstance().get(redisCodeKey);
		} catch (Exception e) {
			RedisUtils.getInstance().del(redisCodeKey);
		}
		if(codeRedis == null){
			return false;
		}
		String code_save = codeRedis.toString().split("\\|")[0];
		long time  = Long.valueOf(codeRedis.toString().split("\\|")[1]);
		if((System.currentTimeMillis() - time) / 1000 > timeoutInt){
			return false;
		}
		if(!smsCode.equals(code_save)){
			return false;
		}
		
		//删除redis验证码和计数
		RedisUtils.getInstance().del(redisCodeKey);
		RedisUtils.getInstance().del(redisNumKey);
		return true;
	}
	
	/**
	 * 发送短信
	 * 
	 * @param mobileNo
	 *            ==》 手机号 
	 * @param smsType
	 *            ==》 发送类型
	 * @return
	 */
	@Override
	public ResponseResult sendSms(String mobileNo, SmsParameter smsParameter, SmsTypeEnum smsType) {
		try {
			if("registerMobileKey".equals(smsType.getTemplateName())){//短信验证码
				return sendAuthenticationCode(mobileNo,smsType);
			}else {
				sendCodeMes(mobileNo,smsParameter,smsType.getTemplateName());
				return ResponseResult.getSuccessResult("发送成功", null);
			}
		} catch (Exception e) {
			MarvelsLogUtil.getInstance().error("发送短信出现异常", e);
			return ResponseResult.getExceptionResult("发送异常");
		}
	}
	/**
	 * 发送短信验证码
	 * @param mobileNo
	 * @param smsParameter
	 * @param smsType
	 */
	private ResponseResult sendAuthenticationCode(String mobileNo, SmsTypeEnum smsType){
		try {
			String smsCode = RandomUtil.randomNumbers(6);
			String redisCodeValue = smsCode + "|" + System.currentTimeMillis();
			String redisCodeKey = smsType.getName() + mobileNo + "code";
			RedisUtils redisUtils = RedisUtils.getInstance();
			/*//需要加入连接短信服务器发送验证码的方法
			String redisNumKey = smsType.getName() + mobileNo + "num";
			
			同一手机，两分钟只能发送一次验证码
			Object codeRedis = redisUtils.get(redisCodeKey);
			if(codeRedis != null){
				long time  = Long.valueOf(codeRedis.toString().split("\\|")[1]);
				if((System.currentTimeMillis() - time) / 1000 < 60){
					MarvelsLogUtil.getInstance().info("验证码发送成功【" + mobileNo + "】发送验证码频繁，一分钟只能发送一次");
					return ResponseResult.getFailResult("发送短信验证码太频繁");
				}
			}
			int sendTimesInt=0;
			验证码一个小时内，只能连续发送三次。当验证码验证通过时，将次数置为零，可重新发送
			Object sendTimes = redisUtils.get(redisNumKey);
			if(sendTimes != null){
				sendTimesInt = Integer.valueOf(sendTimes.toString());
				if(sendTimesInt >= 3){
					MarvelsLogUtil.getInstance().info("验证码发送成功【" + mobileNo + "】发送验证码频繁，没有通过验证的情况下，一个小时内只能发送3次");
					return ResponseResult.getFailResult("发送短信验证码太频繁");
				}
			}*/
			MarvelsLogUtil.getInstance().info("【" + mobileNo + "】send_message_code==>>" + mobileNo+",验证码为：" + smsCode);
			SmsParameter smsParameter = new SmsParameter();
			smsParameter.setSmsCode(smsCode);
			sendCodeMes(mobileNo, smsParameter, smsType.getTemplateName());//异步发送短信验证码
			String timeoutStr = PropertiesUtils.getString("sms.codetimeout");
			redisUtils.setex(redisCodeKey, Integer.parseInt(timeoutStr), redisCodeValue);
//			redisUtils.setex(redisNumKey, 60 * 60, sendTimesInt + 1 + "");
			return ResponseResult.getSuccessResult("发送成功", null);
		} catch (Exception e) {
			MarvelsLogUtil.getInstance().error("发送验证码出现异常", e);
			return ResponseResult.getExceptionResult("发送异常");
		}
	}
	/**
	 * 
	* @Title: sendCodeMes 
	* @Description:  发送短信    
	* @author 李瑶
	* @date 2018年3月26日 下午6:34:04
	 */
	@Async("sendMes")
	private void sendCodeMes(String phone,SmsParameter smsParameter, String templateKey)throws Exception{
		MarvelsLogUtil.getInstance().info("开始发送短信，phone:"+phone+",smsParameter:"+smsParameter);
		SmsTemplateNew contentTemplate = smsTemplateMapper.selectByTemplateCode(templateKey, true);
		
		if(contentTemplate==null){
			throw new Exception("数据库未查询到发短信的模板");
		}
		//模板替换
		String content = replaceContent(contentTemplate.getContentTemplateContent(),smsParameter,templateKey);
		if(StringUtils.isBlank(content)){
			throw new Exception("枚举未查询到发短信的模板");
		}
		SmsLog smsLog = new SmsLog();
		smsLog.setPhone(phone);
		smsLog.setContent(content);
		smsLog.setSendTime(new Date());
		String isUat = PropertiesUtils.getString("sms.isuat");
		if("isprd".equals(isUat)){
			MicroNetResponse microNetResponse = sendMes(phone, content);
			if ("0".equals(microNetResponse.getState())) {
				MarvelsLogUtil.getInstance().info("开始发送短信，phone:"+phone+",smsParameter:"+smsParameter+",发送成功");
				smsLog.setStatus(true);
			} else {
				MarvelsLogUtil.getInstance().info("开始发送短信，phone:"+phone+",smsParameter:"+smsParameter+",发送失败");
				smsLog.setStatus(false);
			}
		}else{//测试环境,不实际发短信
			smsLog.setStatus(true);
		}
		
		smsLogMapper.insert(smsLog);
		MarvelsLogUtil.getInstance().info("开始发送短信，phone:"+phone+",smsParameter:"+smsParameter+",发送结束");
	}
	/**
	 * 
	* @Title: sendMes 
	* @Description: 发送短信接口
	* @param phone
	* @param msg       
	* @author 李瑶
	* @date 2018年3月26日 下午4:34:58
	 */
	private MicroNetResponse sendMes(String phone,String msg)throws Exception{
		String MICRONET_URL = PropertiesUtils.getString("sms.smsUrl");
		String MICRONET_SNAME = PropertiesUtils.getString("sms.smsName");
		String MICRONET_SPWD = PropertiesUtils.getString("sms.smsPwd");
		String suffix = PropertiesUtils.getString("sms.suffix");
		Map<String, Object> map = new HashMap<String, Object>();
		DataRow returndata = new DataRow();
		String returnResult = "";
		map.put("sname", MICRONET_SNAME);
		map.put("spwd", MICRONET_SPWD);
		map.put("scorpid", "");
		map.put("sprdid", "1012888");
		map.put("sdst", phone);
		try {
			map.put("smsg", URLEncoder.encode(msg + "【" + suffix + "】", "UTF-8"));
		} catch (Exception e1) {
			e1.printStackTrace();
			MarvelsLogUtil.getInstance().info("===========>>>互盟短信请求参数拼装异常");
		}
		String requestParams = ThirdSystemUtil.paramsAssembling(map, "");
		MarvelsLogUtil.getInstance().info("=============>>>>互盟短信请求参数:" + requestParams);
		try {
			returnResult = HttpUtil.SMS(requestParams, MICRONET_URL);
			MarvelsLogUtil.getInstance().info("=============>>>>互盟短信返回参数:"+returnResult);
		} catch (Exception e) {
			
			MarvelsLogUtil.getInstance().error(">>>>>>>>>>手机号:"+phone+",互盟短信发送异常:",e);
			throw e;
		}
		MicroNetResponse microNetResponse = new MicroNetResponse();
		microNetResponse.setState("1");
		if (StrUtil.isNotEmpty(returnResult)) {
			returndata = ThirdSystemUtil.xmlToDatarow(returnResult);
			
			microNetResponse.setState(returndata.getString("State"));
			microNetResponse.setMsgID(returndata.getString("MsgID"));
			microNetResponse.setMsgState(returndata.getString("MsgState"));
			microNetResponse.setReserve(returndata.getString("Reserve"));
			//microNetResponse = SystemUtil.xmlToEntity(returnResult, MicroNetResponse.class);//转换方法不兼容异步，所以不用注解转换xml
		}
		//MarvelsLogUtil.getInstance().info("=============>>>>互盟短信返回参数:" + returnResult);
		return microNetResponse;
	}
	/**
	 * 模板替换
	 * @return
	 */
	private String replaceContent(String contentTemplateStr,SmsParameter smsParameter, String templateKey){
		String content = "";
		if(StringUtils.isNoneBlank(contentTemplateStr)){
			content = contentTemplateStr.replace("smsCode", smsParameter.getSmsCode() == null ? "" : smsParameter.getSmsCode())
					.replace("product", smsParameter.getProduct() == null ? "" : smsParameter.getProduct())
					.replace("period", smsParameter.getPeriod() == null ? "" : smsParameter.getPeriod())
					.replace("amount", smsParameter.getAmount() == null ? "" : smsParameter.getAmount())
					.replace("loanDay", smsParameter.getLoanDay() == null ? "" : smsParameter.getLoanDay())
					.replace("repayDay", smsParameter.getRepayDay() == null ? "" : smsParameter.getRepayDay())
					.replace("userName", smsParameter.getUserName() == null ? "" : smsParameter.getUserName())
					.replace("expireDay", smsParameter.getExpireDay() == null ? "" : smsParameter.getExpireDay())
					.replace("overdueDay", smsParameter.getOverdueDay() == null ? "" : smsParameter.getOverdueDay())
					.replace("totalAmount", smsParameter.getTotalAmount() == null ? "" : smsParameter.getTotalAmount())
					.replace("digitsNumber", smsParameter.getDigitsNumber() == null ? "" : smsParameter.getDigitsNumber())
					.replace("bankCard", smsParameter.getBankCard() == null ? "" : smsParameter.getBankCard())
					.replace("bankName", smsParameter.getBankName() == null ? "" : smsParameter.getBankName())
					.replace("bankNum4", smsParameter.getBankCard() == null ? "" : smsParameter.getBankCard());
		}
		return content;
	}

	@Override
	public SmsTemplateNew getSmsTemplateNew(SmsTypeEnum smsTypeEnum) {
		SmsTemplateNew contentTemplate = smsTemplateMapper.selectByTemplateCode(smsTypeEnum.getTemplateName(), true);
		return contentTemplate;
	}
}
